import yaml, random, importlib
import numpy as np

from .basic_planner import basic_planner
from ..satellite_formation import basic_sate_form
from ..file_io import global_output
from tqdm import tqdm
import copy

class darwin_planner(basic_planner):
    '''
    Darwin 科学路径规划算法
    '''
    def __init__(self, yaml_config):
        self.__target_list = None
        self.__sate_form = None
        self.__sigma = yaml_config.get("GaussSigma", 0.5)           # 蚁群算法抽样Gauss的sigma值
        self.__iter_num = yaml_config.get("IterNum", 2000)              # 迭代次数
        self.__csv_task    = "darwin_planner_result"
        self.__csv_results = "darwin_planner_operation"
        self.__min_var = yaml_config.get("MinimizationVariable", "simple_time")
        self.__min_var_config = yaml_config.get("MinimizationConfig", {})

        # 指定最小化变量
        minimize_mod = importlib.import_module(f".minimization_variables.{self.__min_var}", package="miyinff")
        self.__minimize_clz = getattr(minimize_mod, self.__min_var)
        self.__minimize_obj = self.__minimize_clz(self.__min_var_config)

    def param_list(self):
        return self.__minimize_clz.param_list()

    #def sate_form_type(self):
    #    return self.__minimize_clz.sate_form_type()

    def initialize(self, target_list, **kwargs):

        self.__init_target_list, self.__init_sate_form = self.__minimize_obj.initialize(target_list)

        global_output.create_csv_file(self.__csv_task)
        global_output.csv_file[self.__csv_task].write_head("ID")
        global_output.csv_file[self.__csv_task].write_head(self.__init_target_list.param_list)
        global_output.csv_file[self.__csv_task].write_head(["Time", "N_remain", "N_sleep"])

        #self.__init_target_list = target_list
        #self.__init_sate_form = sate_format

        self.__visual_angle = self.__init_sate_form.visual_angle      # 可视角度 deg
        self.__sleep_time   = self.__init_sate_form.sleep_time        # 无观测目标时的等待时间 day

    def init(self):
        self.__target_list = copy.deepcopy(self.__init_target_list)
        self.__sate_form = copy.deepcopy(self.__init_sate_form)
        self.__current_time = 0.

    def operation(self):
        result_list = []
        min_job = [-1, 1e10, -1]
        for i in tqdm(range(self.__iter_num)):
            self.init() 
            result_list.append(self.execute())
            if min_job[1] > result_list[i][1]:
                min_job = result_list[i]
                global_output.csv_file[self.__csv_task].save()
            else:
                global_output.csv_file[self.__csv_task].clear_lines()

        global_output.write_log(f"\nOperation finished, Best Job: {min_job[0]}, Time: {min_job[1]}, Delta angle: {min_job[2]}")
        self.__sate_form.end_operation()
        global_output.create_csv_file(self.__csv_results)
        global_output.csv_file[self.__csv_results].write_table(["iJob", "Time", "DeltaAngle"], result_list)
        global_output.csv_file[self.__csv_results].save()

    def execute(self):
        n_sleep = 0
        delta_angle = 0.
        global_output.new_job()
        while self.__target_list.len > 0:
            # 找到下一个观测目标
            point_angle = self.__sate_form.point_lon
            #target_id, time_cost, self.__sate_form = self.execute()
            #self.__target_list_iter = self.__target_list.nplist
            #self.filter()
            self.__target_list_iter = self.__minimize_obj.filter(self.__target_list.nplist, self.__sate_form)
            target_id, time_cost = self.select()

            # 如无合适目标，则等待一段时间后继续
            if target_id == -1:
                n_sleep = n_sleep + 1
                self.__current_time = self.__current_time + self.__sleep_time
                continue

            self.__current_time = self.__current_time + time_cost
            delta_angle = delta_angle + (np.abs(point_angle - self.__sate_form.point_lon) % 360)

            # 更新信息
            self.__target_list.delete_target(target_id)
            #print(f"Current time: {self.__current_time}. Remaining task: {self.__tg_list.len}")
            global_output.csv_file[self.__csv_task].write_line([self.__current_time, self.__target_list.len, n_sleep], end=True)
            n_sleep = 0

        jobinfo = [global_output.i_job, self.__current_time, delta_angle]
        return jobinfo

    def select(self):
        # 如果无满足条件的待测目标，则等待一段时间
        if(len(self.__target_list_iter) == 0):
            # 更新卫星编队状态
            #self.__sate_form.orbit_lon = self.__sate_form.orbit_lon + self.__sleep_time * self.__sate_form.orbit_rotate_angular_velocity
            #global_output.write_line(-1)
            #return -1, self.__sleep_time
            return self.__sate_form.update_satellite(sleep=True)

        # 计算剩余目标重定向需要的时间
        #target_retarget_time = (self.__target_list_iter[:,1]-self.__sate_form.point_lon) / self.__sate_form.angular_velocity
        delta_lon = np.abs(self.__target_list_iter[:,1]-self.__sate_form.point_lon) % 360
        target_retarget_time = delta_lon / self.__sate_form.angular_velocity

        # 按照总耗时给列表重排序，根据蚁群算法确定目标
        target_finish_time = self.__minimize_obj.evaluate(self.__target_list_iter, self.__sate_form)
        sort_indices = np.argsort(target_finish_time)
        #sort_indices = np.argsort(target_retarget_time + self.__target_list_iter[:,3])
        #sort_indices = np.argsort(target_retarget_time)
        self.__target_list_iter = self.__target_list_iter[sort_indices]
        target_finish_time = target_finish_time[sort_indices]
        num_of_targets = len(self.__target_list_iter)
        index = np.floor(np.abs(np.random.normal(0., self.__sigma)) / (3/num_of_targets))
        if index >= num_of_targets:
            index = num_of_targets - 1
        index = int(index)
        current_target = self.__target_list_iter[index]
        total_time_cost = target_finish_time[index]

        # 更新卫星编队状态
        #self.__sate_form.point_lon = current_target[1]
        #self.__sate_form.point_lat = current_target[2]
        #self.__sate_form.orbit_lon = self.__sate_form.orbit_lon + total_time_cost * self.__sate_form.orbit_rotate_angular_velocity

        # 信息输出
        #print(f"Select target {current_target[0]}, ra: {current_target[1]}, dec: {current_target[2]}, t_tot: {current_target[3]}")
        global_output.csv_file[self.__csv_task].write_line(current_target.tolist(), end=False)
        #return current_target[0], total_time_cost
        return self.__sate_form.update_satellite(current_target, total_time_cost)

    def clear(self):
        pass
